Implement Virtual Tools and Customer Finder Piece for Agent OS#9
Implement Virtual Tools and Customer Finder Piece for Agent OS#9AGI-Corporation wants to merge 4 commits intomainfrom
Conversation
- Added support for Virtual Tools (blended actions) in Mcp entity and server. - Integrated Guido rule-set validation for virtual tools. - Created `customer-finder` community piece with AI-optimized metadata. - Added database migration for `virtualTools` column in `mcp` table. - Updated NANDA manifest to report composition and blended tools. - Implemented `virtualToolService` to handle action blending and rule validation. Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a new "Customer Finder" piece with two actions and related build/config files, and extends MCP with virtualTools support: schema, migration, entity field, server integration (validation-first execution plan), and virtual-tool service adjustments. Changes
Sequence DiagramsequenceDiagram
participant Client as Client/User
participant MCPServer as MCP Server
participant VTService as Virtual Tool Service
Client->>MCPServer: Invoke virtual tool with params
MCPServer->>VTService: validateBlendedData(params, ruleSets)
alt Validation Success
VTService-->>MCPServer: Validation passed (plan)
MCPServer-->>Client: Return validation plan + JSON representation
else Validation Failure
VTService-->>MCPServer: Validation error
MCPServer-->>Client: Return validation error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Added support for Virtual Tools (blended actions) in Mcp entity and server. - Integrated Guido rule-set validation for virtual tools. - Created `customer-finder` community piece with AI-optimized metadata and full Nx configuration. - Added database migration for `virtualTools` column in `mcp` table. - Updated NANDA manifest to report composition and blended tools. - Implemented `virtualToolService` to handle action blending and rule validation. Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a296e6d65b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| version: undefined, | ||
| projectId, | ||
| platformId, | ||
| }).then(metadata => metadata.actions[ba.actionName]) |
There was a problem hiding this comment.
Guard missing base actions before blending virtual tools
If a virtual tool references an action name that is no longer present in a piece (for example after a piece update/rename), metadata.actions[ba.actionName] returns undefined and that value is forwarded into blendActions, which later dereferences action.props and throws. Because this happens inside createMcpServer, the MCP SSE session setup fails and the project’s MCP endpoint becomes unusable until the bad config is fixed. Please validate each base action lookup result and fail/skip with a controlled error before blending.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
packages/server/api/src/app/mcp/mcp-server.ts (1)
172-173: Consider enforcingMAX_TOOL_NAME_LENGTHfor virtual tool names.Other tool registrations (line 60, 211) apply
.slice(0, MAX_TOOL_NAME_LENGTH)to ensure tool names don't exceed the limit. Virtual tools should follow the same pattern for consistency.♻️ Proposed fix
server.tool( - vt.name, + vt.name.slice(0, MAX_TOOL_NAME_LENGTH), blendedAction.description!,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/server/api/src/app/mcp/mcp-server.ts` around lines 172 - 173, Virtual tool registrations call server.tool with vt.name but don't truncate names; apply the same MAX_TOOL_NAME_LENGTH enforcement as elsewhere by slicing vt.name to MAX_TOOL_NAME_LENGTH before passing to server.tool (same pattern used at other registrations such as the ones around server.tool calls at lines near 60 and 211). Update the invocation that uses vt.name to pass vt.name.slice(0, MAX_TOOL_NAME_LENGTH) so virtual tool names are consistently bounded.packages/pieces/community/customer-finder/src/lib/actions/generate-outreach.ts (1)
33-37: Consider explicit guard for unsupportedtonevalues.Current fallback treats any unknown tone as casual. An explicit validation branch would make failures clearer if input contracts drift.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/pieces/community/customer-finder/src/lib/actions/generate-outreach.ts` around lines 33 - 37, The current generator (in the function that reads `tone`, `customer_name`, and `product_service`, e.g., generateOutreach) treats any unknown `tone` as casual; add an explicit validation branch: handle known values explicitly (e.g., "professional" and "casual") and for any other `tone` return a clear error or throw an exception (TypeError) indicating an unsupported tone value so callers fail fast and it’s obvious when input contracts drift; update the branch logic to reference `tone`, `customer_name`, and `product_service` so the new validation replaces the implicit fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/pieces/community/customer-finder/package.json`:
- Line 6: The package.json "main" entry currently points to TypeScript source
("src/index.ts") which is incorrect; either remove the "main" field or update it
to point to the compiled output (e.g., "dist/out-tsc/index.js" or the project's
compiled entry) so consumers resolve JS at runtime; update the package.json
"main" key accordingly and ensure it matches the output path produced by the
build step used by publish-piece.ts.
In `@packages/pieces/community/customer-finder/src/lib/actions/find-leads.ts`:
- Around line 35-39: The generated email domain uses companyName with only
spaces stripped, which allows invalid characters (e.g., "&", punctuation,
accents); update the code in find-leads.ts where companyName is built and where
email is created to sanitize and normalize the domain: transform companyName to
lowercase, replace ampersands with "and", remove or replace any non-alphanumeric
characters (excluding hyphen), strip diacritics/accents, and collapse multiple
separators before appending the TLD so the email in the leads.push entry is
always a valid domain string.
In
`@packages/server/api/src/app/database/migration/postgres/1745000000000-AddVirtualToolsToMcp.ts`:
- Around line 1-19: Add the new migration class
AddVirtualToolsToMcp1745000000000 to the migration registration so it runs:
import AddVirtualToolsToMcp1745000000000 from the postgres migration file and
insert it into the commonMigration array in postgres-connection.ts in correct
timestamp order; then create a SQLite equivalent migration file named
1745000000000-AddVirtualToolsToMcpSqlite.ts that uses SQLite syntax (ALTER TABLE
"mcp" ADD COLUMN "virtualTools" TEXT) and import/register that new migration in
sqlite-connection.ts (add to the migrations array) so dev/test DBs match
production.
In `@packages/server/api/src/app/mcp/mcp-server.ts`:
- Around line 160-167: The mapped lookup of actions in blendedActions can
produce undefined when metadata.actions[ba.actionName] is missing; update the
vt.baseActions mapping (the async function inside Promise.all that calls
pieceMetadataService(...)) to validate the lookup result: assign const action =
metadata.actions[ba.actionName]; if (!action) throw a clear error (including
ba.pieceName and ba.actionName and projectId/platformId) or otherwise
filter/handle the missing case before returning, so blendActions is never called
with undefined.
In `@packages/server/api/src/app/mcp/virtual-tool-service.ts`:
- Around line 43-45: The loop over ruleSets destructures { conditions, targets }
from each rule but doesn't guard against missing properties; change the logic in
the rule processing (the for ... of ruleSets block that computes conditionMet)
to validate and coerce these fields before use (e.g., treat missing/non-array
conditions as an empty array so conditions.every(...) is safe and verify targets
is an array before iterating/using it), and add a short early-continue or
error-log if a rule's structure is invalid; update the computation that sets
conditionMet and any subsequent use of targets in the same block (referencing
the rule variable, conditions, targets, and conditionMet) to rely on these
defensive checks.
---
Nitpick comments:
In
`@packages/pieces/community/customer-finder/src/lib/actions/generate-outreach.ts`:
- Around line 33-37: The current generator (in the function that reads `tone`,
`customer_name`, and `product_service`, e.g., generateOutreach) treats any
unknown `tone` as casual; add an explicit validation branch: handle known values
explicitly (e.g., "professional" and "casual") and for any other `tone` return a
clear error or throw an exception (TypeError) indicating an unsupported tone
value so callers fail fast and it’s obvious when input contracts drift; update
the branch logic to reference `tone`, `customer_name`, and `product_service` so
the new validation replaces the implicit fallback.
In `@packages/server/api/src/app/mcp/mcp-server.ts`:
- Around line 172-173: Virtual tool registrations call server.tool with vt.name
but don't truncate names; apply the same MAX_TOOL_NAME_LENGTH enforcement as
elsewhere by slicing vt.name to MAX_TOOL_NAME_LENGTH before passing to
server.tool (same pattern used at other registrations such as the ones around
server.tool calls at lines near 60 and 211). Update the invocation that uses
vt.name to pass vt.name.slice(0, MAX_TOOL_NAME_LENGTH) so virtual tool names are
consistently bounded.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3549a700-c986-42f5-8cfb-524d8ad28756
📒 Files selected for processing (10)
packages/pieces/community/customer-finder/package.jsonpackages/pieces/community/customer-finder/src/index.tspackages/pieces/community/customer-finder/src/lib/actions/find-leads.tspackages/pieces/community/customer-finder/src/lib/actions/generate-outreach.tspackages/server/api/src/app/database/migration/postgres/1745000000000-AddVirtualToolsToMcp.tspackages/server/api/src/app/mcp/mcp-entity.tspackages/server/api/src/app/mcp/mcp-server.tspackages/server/api/src/app/mcp/nanda-manifest-service.tspackages/server/api/src/app/mcp/virtual-tool-service.tspackages/shared/src/lib/mcp/mcp.ts
| "displayName": "Customer Finder", | ||
| "version": "0.1.0", | ||
| "description": "AI-powered tool to find target customers and generate outreach copy.", | ||
| "main": "src/index.ts", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Compare entrypoint conventions across community piece package manifests
fd package.json packages/pieces/community | while read -r file; do
if rg -q '"name":\s*"@activepieces/piece-' "$file"; then
echo "---- $file ----"
rg -n '"name"|"main"|"types"|"files"' "$file"
fi
doneRepository: AGI-Corporation/Route.X
Length of output: 29311
🏁 Script executed:
# Check for build configuration and tsconfig
ls -la packages/pieces/community/customer-finder/Repository: AGI-Corporation/Route.X
Length of output: 626
🏁 Script executed:
# Check root-level tsconfig and build setup
cat -n tsconfig.json | head -50Repository: AGI-Corporation/Route.X
Length of output: 112
🏁 Script executed:
# Look for build scripts in the repo
rg -n "build|tsc|dist" packages/pieces/community/customer-finder/package.jsonRepository: AGI-Corporation/Route.X
Length of output: 49
🏁 Script executed:
# Read customer-finder package.json in full
cat -n packages/pieces/community/customer-finder/package.jsonRepository: AGI-Corporation/Route.X
Length of output: 438
🏁 Script executed:
# Read a few other piece package.json files to confirm they lack "main"
cat -n packages/pieces/community/slack/package.jsonRepository: AGI-Corporation/Route.X
Length of output: 158
🏁 Script executed:
# Check root build or publish config
fd "package.json|tsconfig|nx.json|.npmignore" . -maxdepth 2 | head -20Repository: AGI-Corporation/Route.X
Length of output: 297
🏁 Script executed:
# Look for build scripts in root package.json
cat -n package.json | grep -A 50 '"scripts"'Repository: AGI-Corporation/Route.X
Length of output: 3224
🏁 Script executed:
# Check the publish-piece script
cat -n tools/scripts/pieces/publish-piece.ts | head -80Repository: AGI-Corporation/Route.X
Length of output: 1960
🏁 Script executed:
# Look for any build or dist configuration for pieces
find packages/pieces -name "*.json" -type f | xargs grep -l "dist\|build\|outDir" | head -10Repository: AGI-Corporation/Route.X
Length of output: 655
🏁 Script executed:
# Check if there's a standard tsconfig for pieces
find packages/pieces -name "tsconfig*.json" -type f | head -5 | xargs catRepository: AGI-Corporation/Route.X
Length of output: 1897
Remove the incorrect main entrypoint or point to compiled output.
The main field should not reference TypeScript source. All other community pieces omit this field, or—if included—it must point to compiled JavaScript in the dist directory, since the build process (line 26 of publish-piece.ts) explicitly compiles TypeScript to dist/out-tsc before publishing. Consumers will fail to resolve src/index.ts at runtime.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/pieces/community/customer-finder/package.json` at line 6, The
package.json "main" entry currently points to TypeScript source ("src/index.ts")
which is incorrect; either remove the "main" field or update it to point to the
compiled output (e.g., "dist/out-tsc/index.js" or the project's compiled entry)
so consumers resolve JS at runtime; update the package.json "main" key
accordingly and ensure it matches the output path produced by the build step
used by publish-piece.ts.
| const companyName = `${niche} ${suffixes[i % suffixes.length]}`; | ||
| leads.push({ | ||
| name: companyName, | ||
| email: `contact@${companyName.replace(/\s+/g, '').toLowerCase()}.com`, | ||
| location: location, |
There was a problem hiding this comment.
Sanitize generated email domain more robustly.
Line 38 only strips spaces. Inputs like R&D Agencies can produce invalid domains (e.g., contact@r&dagencieshub.com).
Proposed fix
- const companyName = `${niche} ${suffixes[i % suffixes.length]}`;
+ const companyName = `${niche} ${suffixes[i % suffixes.length]}`;
+ const domain = companyName
+ .toLowerCase()
+ .replace(/[^a-z0-9]/g, '');
leads.push({
name: companyName,
- email: `contact@${companyName.replace(/\s+/g, '').toLowerCase()}.com`,
+ email: `contact@${domain || 'lead'}.com`,
location: location,
relevance_score: 0.95 - (i * 0.05),
source: 'AI Discovery'
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const companyName = `${niche} ${suffixes[i % suffixes.length]}`; | |
| leads.push({ | |
| name: companyName, | |
| email: `contact@${companyName.replace(/\s+/g, '').toLowerCase()}.com`, | |
| location: location, | |
| const companyName = `${niche} ${suffixes[i % suffixes.length]}`; | |
| const domain = companyName | |
| .toLowerCase() | |
| .replace(/[^a-z0-9]/g, ''); | |
| leads.push({ | |
| name: companyName, | |
| email: `contact@${domain || 'lead'}.com`, | |
| location: location, | |
| relevance_score: 0.95 - (i * 0.05), | |
| source: 'AI Discovery' | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/pieces/community/customer-finder/src/lib/actions/find-leads.ts`
around lines 35 - 39, The generated email domain uses companyName with only
spaces stripped, which allows invalid characters (e.g., "&", punctuation,
accents); update the code in find-leads.ts where companyName is built and where
email is created to sanitize and normalize the domain: transform companyName to
lowercase, replace ampersands with "and", remove or replace any non-alphanumeric
characters (excluding hyphen), strip diacritics/accents, and collapse multiple
separators before appending the TLD so the email in the leads.push entry is
always a valid domain string.
| import { MigrationInterface, QueryRunner } from 'typeorm' | ||
|
|
||
| export class AddVirtualToolsToMcp1745000000000 implements MigrationInterface { | ||
| name = 'AddVirtualToolsToMcp1745000000000' | ||
|
|
||
| public async up(queryRunner: QueryRunner): Promise<void> { | ||
| await queryRunner.query(` | ||
| ALTER TABLE "mcp" | ||
| ADD "virtualTools" jsonb | ||
| `) | ||
| } | ||
|
|
||
| public async down(queryRunner: QueryRunner): Promise<void> { | ||
| await queryRunner.query(` | ||
| ALTER TABLE "mcp" DROP COLUMN "virtualTools" | ||
| `) | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify migration registration and SQLite variant
echo "=== Checking postgres-connection.ts for migration import ==="
rg -n "AddVirtualToolsToMcp" packages/server/api/src/app/database/postgres-connection.ts 2>&1 || echo "Not found"
echo ""
echo "=== Checking sqlite-connection.ts for migration ==="
rg -n "AddVirtualToolsToMcp" packages/server/api/src/app/database/sqlite-connection.ts 2>&1 || echo "Not found"
echo ""
echo "=== Checking for SQLite migration file ==="
fd -t f ".*AddVirtualTools.*" packages/server/api/src/app/database/migration/sqlite/ 2>&1 || echo "No SQLite variant found"
echo ""
echo "=== Checking all migration files matching pattern ==="
fd -t f "1745000000000" packages/server/api/src/app/database/migration/
echo ""
echo "=== Viewing postgres-connection.ts migration imports section ==="
head -100 packages/server/api/src/app/database/postgres-connection.ts | rg -A 50 "import.*Migration|commonMigration"Repository: AGI-Corporation/Route.X
Length of output: 6311
Migration is not registered and will not execute.
This migration file exists but is not imported or registered in packages/server/api/src/app/database/postgres-connection.ts. Without registration in the migrations array, TypeORM will never execute this migration, and the virtualTools column will not be created in the database. Additionally, there is no SQLite variant of this migration, causing dev/test environments using SQLite to diverge from production PostgreSQL.
Required fixes:
- Import and register in
postgres-connection.ts:
import { AddVirtualToolsToMcp1745000000000 } from './migration/postgres/1745000000000-AddVirtualToolsToMcp'Add to the commonMigration array in the appropriate timestamp order.
- Create SQLite variant at
packages/server/api/src/app/database/migration/sqlite/1745000000000-AddVirtualToolsToMcpSqlite.tsusing SQLite syntax (ALTER TABLE "mcp" ADD COLUMN "virtualTools" TEXT) and register it insqlite-connection.ts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@packages/server/api/src/app/database/migration/postgres/1745000000000-AddVirtualToolsToMcp.ts`
around lines 1 - 19, Add the new migration class
AddVirtualToolsToMcp1745000000000 to the migration registration so it runs:
import AddVirtualToolsToMcp1745000000000 from the postgres migration file and
insert it into the commonMigration array in postgres-connection.ts in correct
timestamp order; then create a SQLite equivalent migration file named
1745000000000-AddVirtualToolsToMcpSqlite.ts that uses SQLite syntax (ALTER TABLE
"mcp" ADD COLUMN "virtualTools" TEXT) and import/register that new migration in
sqlite-connection.ts (add to the migrations array) so dev/test DBs match
production.
| const blendedActions = await Promise.all(vt.baseActions.map(async (ba: any) => { | ||
| return pieceMetadataService(logger).getOrThrow({ | ||
| name: ba.pieceName, | ||
| version: undefined, | ||
| projectId, | ||
| platformId, | ||
| }).then(metadata => metadata.actions[ba.actionName]) | ||
| })) |
There was a problem hiding this comment.
Potential undefined action when actionName doesn't exist in piece metadata.
If ba.actionName doesn't match any action in the piece's metadata, metadata.actions[ba.actionName] returns undefined. This undefined is then passed to blendActions(), which will throw when accessing action.props at line 20 of virtual-tool-service.ts.
🐛 Proposed fix to validate action existence
const blendedActions = await Promise.all(vt.baseActions.map(async (ba: any) => {
- return pieceMetadataService(logger).getOrThrow({
+ const metadata = await pieceMetadataService(logger).getOrThrow({
name: ba.pieceName,
version: undefined,
projectId,
platformId,
- }).then(metadata => metadata.actions[ba.actionName])
+ })
+ const action = metadata.actions[ba.actionName]
+ if (!action) {
+ throw new Error(`Action '${ba.actionName}' not found in piece '${ba.pieceName}'`)
+ }
+ return action
}))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/server/api/src/app/mcp/mcp-server.ts` around lines 160 - 167, The
mapped lookup of actions in blendedActions can produce undefined when
metadata.actions[ba.actionName] is missing; update the vt.baseActions mapping
(the async function inside Promise.all that calls pieceMetadataService(...)) to
validate the lookup result: assign const action =
metadata.actions[ba.actionName]; if (!action) throw a clear error (including
ba.pieceName and ba.actionName and projectId/platformId) or otherwise
filter/handle the missing case before returning, so blendActions is never called
with undefined.
| for (const rule of ruleSets) { | ||
| const { conditions, targets } = rule | ||
| const conditionMet = conditions.every((c: any) => { |
There was a problem hiding this comment.
Add defensive checks for rule structure to prevent runtime errors.
If a rule object lacks conditions or targets properties, destructuring will produce undefined, and calling .every() on undefined will throw a TypeError.
🛡️ Proposed defensive fix
for (const rule of ruleSets) {
const { conditions, targets } = rule
+ if (!Array.isArray(conditions) || !Array.isArray(targets)) {
+ continue
+ }
const conditionMet = conditions.every((c: any) => {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (const rule of ruleSets) { | |
| const { conditions, targets } = rule | |
| const conditionMet = conditions.every((c: any) => { | |
| for (const rule of ruleSets) { | |
| const { conditions, targets } = rule | |
| if (!Array.isArray(conditions) || !Array.isArray(targets)) { | |
| continue | |
| } | |
| const conditionMet = conditions.every((c: any) => { |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/server/api/src/app/mcp/virtual-tool-service.ts` around lines 43 -
45, The loop over ruleSets destructures { conditions, targets } from each rule
but doesn't guard against missing properties; change the logic in the rule
processing (the for ... of ruleSets block that computes conditionMet) to
validate and coerce these fields before use (e.g., treat missing/non-array
conditions as an empty array so conditions.every(...) is safe and verify targets
is an array before iterating/using it), and add a short early-continue or
error-log if a rule's structure is invalid; update the computation that sets
conditionMet and any subsequent use of targets in the same block (referencing
the rule variable, conditions, targets, and conditionMet) to rely on these
defensive checks.
- Added support for Virtual Tools (blended actions) in Mcp entity and server. - Integrated Guido rule-set validation for virtual tools. - Created `customer-finder` community piece with AI-optimized metadata and full Nx configuration. - Added database migration for `virtualTools` column in `mcp` table. - Updated NANDA manifest to report composition and blended tools. - Implemented `virtualToolService` to handle action blending and rule validation. Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
- Added support for Virtual Tools (blended actions) in Mcp entity and server. - Integrated Guido rule-set validation for virtual tools. - Created `customer-finder` community piece with AI-optimized metadata and full Nx configuration. - Added database migration for `virtualTools` column in `mcp` table. - Updated NANDA manifest to report composition and blended tools. - Implemented `virtualToolService` to handle action blending and rule validation. Co-authored-by: AGI-Corporation <186229839+AGI-Corporation@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/pieces/community/customer-finder/.eslintrc.json (1)
8-31: Consolidate redundant empty override blocks.These overlapping overrides all have empty
rules, so they can be simplified to reduce config noise.♻️ Proposed simplification
"overrides": [ { "files": [ "*.ts", "*.tsx", "*.js", "*.jsx" ], "rules": {} - }, - { - "files": [ - "*.ts", - "*.tsx" - ], - "rules": {} - }, - { - "files": [ - "*.js", - "*.jsx" - ], - "rules": {} } ]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/pieces/community/customer-finder/.eslintrc.json` around lines 8 - 31, Merge the three empty override objects inside the overrides array into a single override entry: replace the separate objects that list ["*.ts","*.tsx","*.js","*.jsx"], ["*.ts","*.tsx"], and ["*.js","*.jsx"] (each with empty "rules") with one override containing the combined "files" pattern (e.g., ["*.ts","*.tsx","*.js","*.jsx"]) and a single empty "rules" object, removing the redundant override objects; ensure you update the "overrides" array to contain only that consolidated override.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/pieces/community/customer-finder/README.md`:
- Line 8: Update the README description for the customer-finder piece to make it
explicit that lead discovery is simulated rather than performing real-world
lookups; edit the sentence "Finds target customers based on a niche and location
using AI-driven discovery." in the package README for the customer-finder piece
to state that results are synthetic/simulated AI-generated leads for
demonstration or prototyping (mention "simulated" or "synthetic" and add a short
qualifier like "for demo/prototyping purposes, not real-world contact data").
---
Nitpick comments:
In `@packages/pieces/community/customer-finder/.eslintrc.json`:
- Around line 8-31: Merge the three empty override objects inside the overrides
array into a single override entry: replace the separate objects that list
["*.ts","*.tsx","*.js","*.jsx"], ["*.ts","*.tsx"], and ["*.js","*.jsx"] (each
with empty "rules") with one override containing the combined "files" pattern
(e.g., ["*.ts","*.tsx","*.js","*.jsx"]) and a single empty "rules" object,
removing the redundant override objects; ensure you update the "overrides" array
to contain only that consolidated override.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c95ae65e-fb1b-4d12-8afd-2db75b4c6982
📒 Files selected for processing (5)
packages/pieces/community/customer-finder/.eslintrc.jsonpackages/pieces/community/customer-finder/README.mdpackages/pieces/community/customer-finder/project.jsonpackages/pieces/community/customer-finder/tsconfig.jsonpackages/pieces/community/customer-finder/tsconfig.lib.json
✅ Files skipped from review due to trivial changes (1)
- packages/pieces/community/customer-finder/tsconfig.lib.json
| ## Actions | ||
|
|
||
| ### Find Target Leads | ||
| Finds target customers based on a niche and location using AI-driven discovery. |
There was a problem hiding this comment.
Clarify that lead discovery is simulated.
Current wording can be read as real-world lead lookup. Given this piece simulates discovery, docs should explicitly say so.
📝 Suggested wording
-Finds target customers based on a niche and location using AI-driven discovery.
+Finds simulated target customers based on niche and location using AI-generated metadata.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Finds target customers based on a niche and location using AI-driven discovery. | |
| Finds simulated target customers based on niche and location using AI-generated metadata. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/pieces/community/customer-finder/README.md` at line 8, Update the
README description for the customer-finder piece to make it explicit that lead
discovery is simulated rather than performing real-world lookups; edit the
sentence "Finds target customers based on a niche and location using AI-driven
discovery." in the package README for the customer-finder piece to state that
results are synthetic/simulated AI-generated leads for demonstration or
prototyping (mention "simulated" or "synthetic" and add a short qualifier like
"for demo/prototyping purposes, not real-world contact data").
This PR enhances the Activepieces Agent OS framework by completing the integration of Virtual Tools (blended actions) and providing a practical application for customer acquisition.
Key changes:
Virtual Tools Infrastructure:
Mcpshared type andMcpEntityto supportvirtualToolsconfiguration.virtualToolsJSONB column.virtualToolServicefor aggregating properties and validating rule-sets.McpServerto register these virtual tools, providing an intuitive interface for complex workflows.Customer Finder Piece:
@activepieces/piece-customer-finder.find_leads: Uses AI-ready metadata to simulate lead discovery based on niche and location.generate_outreach: Generates personalized outreach copy with adjustable tones.NANDA Protocol Improvements:
These changes make the platform more intuitive for AI agents (Cactus-ready) and provide a ready-to-use toolkit for users looking to automate customer acquisition.
PR created automatically by Jules for task 14452167465071627437 started by @AGI-Corporation
Summary by CodeRabbit